/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.

需求分析
1. Promise是一个类 构建这个类的实例对象时 需要传入一个构造器 构造器会立即执行
   构造器包含两个参数 分别是resolve和reject方法 resolve方法需要一个value参数用来传递成功时的值 reject方法需要一个reason参数用来传递失败原因
2. promise实例对象有三种状态 分别是 pending等待 fulfilled成功 rejected失败
   状态只能从等待变为成功 或 从等待变为失败 成功和失败后状态不可变
3. promise实例对象有then方法 该方法需要两个参数 分别为成功后的回调 (value) => { ... } 和失败后的回调 (reason) => { ... }
   其中 value 和 reason 分别是 构造器中 resolve 和 reject 方法传入的参数
4. promise状态支持异步推进
5. promise的then方法支持链式调用 且 then方法返回的promise对象并不是初次调用then方法的promise对象
   then方法的链式调用同样支持异步推进状态
6. then方法链式调用时 后面的then方法的回调函数拿到的值是前一个then方法的回调函数的返回值
   如果返回的是一个promise对象 则使用返回的promise对象作为后面then方法的调用者
*/

const PENDING = "pending"       // 等待状态
const FULFILLED = "fulfilled"   // 成功状态
const REJECTED = "rejected"     // 失败状态

class MyPromise {
    constructor (executor) {
        // 构造器的executor方法会立即执行 并且接收两个参数
        // 分别是将promise推进至成功状态的resolve方法和将promise推进至失败状态的reject方法
        // 所以分别定义了两个方法用来存放这两个参数
        executor(this.resolve, this.reject)
    }

    // promise对象的默认状态是等待
    status = PENDING

    // 用来存放resolve方法中获取到的值
    value = undefined
    // 用来存放reject方法中获取到的失败原因
    reason = undefined

    // 用来存放从构造器的执行方法中获取到的resolve方法
    resolve = (value) => {
        // 状态只能由等待向后推进 非等待状态直接退出函数执行
        if (this.status !== PENDING) return
        // 将状态推进至成功
        this.status = FULFILLED
        // 存储值
        this.value = value
        // 如果状态是异步推进至此且有需要执行的回调函数 那么执行此回调函数
        if (this.onFulfilled) {
            // 如果then方法的成功回调内有返回值 则将以此返回值为值传入后面链式调用的then中
            var onFulfilledReturn = this.onFulfilled(value)
            // 异步的状态推进需要让then方法的链式调用状态同样得到推进
            this.afterThen.resolve(onFulfilledReturn ? onFulfilledReturn : value)
        }
    }
    // 用来存放从构造器的执行方法中获取到的reject方法
    reject = (reason) => {
        // 状态只能由等待向后推进 非等待状态直接退出函数执行
        if (this.status !== PENDING) return
        // 将状态推进至失败
        this.status = REJECTED
        // 存储失败原因
        this.reason = reason
        // 如果状态是异步推进至此且有需要执行的回调函数 那么执行此回调函数
        if (this.onRejected) {
            this.onRejected(reason)
            // 异步的状态推进需要让then方法的链式调用状态同样得到推进
            this.afterThen.resolve()
        }
    }

    // 用来存放状态推进至成功时需要执行的回调函数
    onFulfilled = undefined
    // 用来存放状态推进至成功时需要执行的回调函数
    onRejected = undefined

    // 用来存放then方法返回的promise对象 方便异步推进then后续链式调用时的状态
    afterThen = undefined

    // then方法接收两个参数 分别是状态为成功时会执行的onFulfilled方法 和 状态为失败时执行的onRejected方法
    then (onFulfilled, onRejected) {
        var onFulfilledReturn
        // 创建promise对象用于返回后供then方法链式调用
        let promise = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED) { // 状态为成功时 执行onFulfilled 并将 值 以参数形式传递进方法内
                // 如果then方法的成功回调内有返回值 则将以此返回值为值传入后面链式调用的then中
                onFulfilledReturn = onFulfilled(this.value)
                // 将成功状态向后传递 便于后续链式调用的then方法接收成功状态及值 
                if (!(onFulfilledReturn instanceof MyPromise)) resolve(onFulfilledReturn ? onFulfilledReturn : this.value)
            } else if (this.status === REJECTED) { // 状态为失败时 执行onRejected 并将 失败原因 以参数形式传递进方法内
                onRejected(this.reason)
                // 将失败状态向后传递 便于后续链式调用的then方法接收失败状态及失败原因
                reject(this.reason)
            } else { // 状态为等待时 为了promise状态被异步推进时还能执行成功或失败的回调方法 需要将回调函数进行存储
                this.onFulfilled = onFulfilled
                this.onRejected = onRejected
                // 存储返回的promise对象 便于异步状态推进时的then方法链式调用 微任务更符合promise的异步任务优先级
                queueMicrotask(() => {
                    this.afterThen = onFulfilledReturn instanceof MyPromise ? onFulfilledReturn : promise
                })
            }
        })
        // 如果then方法的成功回调内有返回值 且返回值为一个promise对象 则将以此返回值作为后面链式调用then的调用者
        if (onFulfilledReturn && (onFulfilledReturn instanceof MyPromise)) return onFulfilledReturn
        return promise
    }
}

// 导出MyPromise类
module.exports = MyPromise